package hypeerweb;

import states.HypercubeCapState;

public class AddCommand extends Command
{

 

    @Override
    public boolean isExtreme(Node currNode)
    {
        if(currNode.getState().getId() == HypercubeCapState.STATE_ID)
        {
            return true;
        }
        else
        {
            return false;
        }
  
    }

    @Override
    public Node goExtreme(Node currNode)
    {
        return currNode.findCapNode();
    }
 
    @Override
    public boolean isOpPoint(Node currNode)
    {
        Node temp = currNode;
        temp = goOpPoint(currNode);
        if(temp == currNode)
        {
            return true;//it is the extreme
        }
        else
        {
            return false;//it isn't the extreme
        }
    }

    @Override
    public Node goOpPoint(Node currNode)
    {
        Node nextPoint = currNode;
        for(Node n: currNode.getNeighbors())
        {
            if ((hasUpPointers(currNode) && hasUpPointers(n) 
                    && n.getWebId().getValue() < nextPoint.getWebId().getValue()) ||
               (!hasUpPointers(currNode)                      
                    && n.getWebId().getValue() < nextPoint.getWebId().getValue()) )
            {
                   nextPoint = n;
            }
        }
        return nextPoint;
    }

    @Override
    // what is opNode and what is opPoint??? figure this out and then replace all 
    //opNodes and opPoints
    
    public void connect(Node opNode, Node opPoint)
    {
        opNode.setWebId(opPoint.getWebId().createChildsWebId());
        opPoint.incrementHeight();
        //opPoint.getWebId().incrementHeight();
        if(opPoint.getWebId().getValue() == 0 
                && opPoint.getState().getId() == HypercubeCapState.STATE_ID)
        {
            opPoint.setFold(opNode);
            opNode.setFold(opPoint);
            opPoint.setSurrogateFold(Node.NULL_NODE);
            opPoint.setInverseSurrogateFold(Node.NULL_NODE);
            opNode.setSurrogateFold(Node.NULL_NODE);
            opNode.setInverseSurrogateFold(Node.NULL_NODE);
        }
        else
        {
            if(opPoint.getInverseSurrogateFold().getWebId().getValue() != 
                                  Node.NULL_NODE.getWebId().getValue())
            {
                // opNode gets opPoint's inverse surrogate fold
                opNode.setFold(opPoint.getInverseSurrogateFold());
                // tell the new fold that it has a fold.
                opNode.getFold().setFold(opNode);
                // tell the new fold it does not have a surrogate fold now.
                opNode.getFold().setSurrogateFold(Node.NULL_NODE);
                opNode.setSurrogateFold(Node.NULL_NODE);
                opNode.setInverseSurrogateFold(Node.NULL_NODE);
                opPoint.setSurrogateFold(Node.NULL_NODE);
                opPoint.setInverseSurrogateFold(Node.NULL_NODE);
            }
            else
            {
                // opNode gets opPoint's fold
                opNode.setFold(opPoint.getFold());
                // tell the new fold that it has a fold.
                opNode.getFold().setFold(opNode);
                opNode.setSurrogateFold(Node.NULL_NODE);
                opNode.setInverseSurrogateFold(Node.NULL_NODE);
                // parents fold becomes it's surrogate fold.
                opPoint.setSurrogateFold(opPoint.getFold());
                // tell the new surrogate it has an inverse surrogate.
                opPoint.getSurrogateFold().setInverseSurrogateFold(opPoint);
                opPoint.setFold(Node.NULL_NODE);
                opPoint.setInverseSurrogateFold(Node.NULL_NODE);
            }
        }
        for(Node n: opPoint.getUpPointers())
        {
            opNode.addNeighbor(n);
            n.addNeighbor(opNode);
            n.removeDownPointer(opPoint);
            n.updateState();
        }
        opPoint.clearUpPointers();
        for(Node n: opPoint.getNeighbors())
        {
            if(n.getWebId().getValue() > opPoint.getWebId().getValue())
            {
                opNode.addDownPointer(n);
                n.addUpPointer(opNode);
            }
        }
        opNode.setState(opPoint.getChildState());
        opPoint.updateState();
        opPoint.addNeighbor(opNode);
        opNode.addNeighbor(opPoint);
        
    }
    private boolean hasUpPointers(Node node)
    {
        return !node.getUpPointers().isEmpty();
    }

}
